Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

packer_test: make packer test suite modular #13041

Merged
merged 5 commits into from
Aug 13, 2024

Conversation

lbajolet-hashicorp
Copy link
Contributor

@lbajolet-hashicorp lbajolet-hashicorp commented Jun 12, 2024

Having only one test suite for the whole of Packer makes it harder to segregate between test types, and makes for a longer runtime as no tests run in parallel by default.

This commit splits the packer_test suite into several components in order to make extension easier.

First we have lib: this package embeds the core for running Packer test suites. This ships facilities to build your own test suite for Packer core, and exposes convenience methods and structures for building plugins, packer core, and use it to run a test suite in a temporary directory.

Then we have two separate test suites: one for plugins, and one for core itself, the latter of which does not depend on plugins being compiled at all.

This sets the stage for more specialised test suites in the future, each of which can run in parallel on different parts of the code.

@lbajolet-hashicorp lbajolet-hashicorp added enhancement tech-debt Issues and pull requests related to addressing technical debt or improving the codebase labels Jun 12, 2024
@lbajolet-hashicorp lbajolet-hashicorp requested a review from a team as a code owner June 12, 2024 20:07
@lbajolet-hashicorp lbajolet-hashicorp force-pushed the split_packer_test_suites branch from 1454020 to e7ab35c Compare June 12, 2024 20:08
@lbajolet-hashicorp lbajolet-hashicorp changed the base branch from main to fix_locals_eval_order June 12, 2024 20:08
@lbajolet-hashicorp lbajolet-hashicorp force-pushed the split_packer_test_suites branch from e7ab35c to d86199e Compare June 12, 2024 20:25
@lbajolet-hashicorp lbajolet-hashicorp changed the base branch from fix_locals_eval_order to main June 13, 2024 14:51
@lbajolet-hashicorp lbajolet-hashicorp marked this pull request as draft June 13, 2024 14:57
@@ -1,4 +1,4 @@
package packer_test
package lib
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to dive into these changes further. But I hesitate to treat this as a separate package. I changed the name to packer_test, as that is the Go idiom for denoting that this is a test package, which does not have direct access to anything in the packer package and also to ensure that the package is excluded from the final binary.

Previously, the go files ended with _test. go, which are excluded from the binary. It looks like this refactor changes that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think the code will not be part of the final binary still, as it's not transitively imported from main.go, that said if you think that the package name is a problem, we can still move the lib files back to the upper package so that packages using the test suite will still include something called _test.

@lbajolet-hashicorp lbajolet-hashicorp force-pushed the split_packer_test_suites branch from 3b62757 to 90d99b0 Compare June 14, 2024 13:38
@lbajolet-hashicorp lbajolet-hashicorp changed the base branch from main to fix_locals_eval_order June 14, 2024 13:38
@lbajolet-hashicorp lbajolet-hashicorp force-pushed the split_packer_test_suites branch from 90d99b0 to 2e91694 Compare June 14, 2024 13:58
@lbajolet-hashicorp lbajolet-hashicorp force-pushed the fix_locals_eval_order branch 3 times, most recently from 1fcfafa to 7823d15 Compare June 17, 2024 16:33
Base automatically changed from fix_locals_eval_order to main June 17, 2024 20:52
@lbajolet-hashicorp lbajolet-hashicorp force-pushed the split_packer_test_suites branch from 2e91694 to e24d4f0 Compare June 17, 2024 20:56
@lbajolet-hashicorp lbajolet-hashicorp marked this pull request as ready for review June 17, 2024 20:56
@lbajolet-hashicorp lbajolet-hashicorp changed the title Split packer test suites packer_test: make packer test suite modular Jun 17, 2024
@lbajolet-hashicorp lbajolet-hashicorp force-pushed the split_packer_test_suites branch from e24d4f0 to bc8c395 Compare June 17, 2024 20:58
Copy link
Contributor

@nywilken nywilken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still working through this but my initial review leaves me with more questions than answers. What would you say is the benefit to the refactor?

@@ -1,8 +1,12 @@
package packer_test
package core_test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why core_test? What information does it provide that packer_test may not?

Comment on lines +10 to +15
type PackerCoreTestSuite struct {
*lib.PackerTestSuite
}

func Test_PackerPluginSuite(t *testing.T) {
baseSuite, cleanup := lib.PackerCoreSuite(t)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the need for PackerCoreTestSuite over lib.PackerTestSuite and how they relate or differ from lib.PackerCoreSuite(). Is this level of abstraction offering a benefit that may not be immediately noticeable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the difference between the two is mostly that the tests run are not the same, being two separate packages/instances of TestSuite means that both can run in parallel. They also may not have the same needs for plugins for example, so one will have to compile a bunch of plugins, and others don't.
As for the names right now, I picked something somewhat randomly, I'm completely open to rename them to something else if you think it's confusing, no problems here!

@@ -1,6 +1,8 @@
package packer_test
package plugin_tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now why you chose core_test above. This feels like unneeded package nesting to split the tests. These are all Packer command tests. In fact it appears that this package offers nothing new besides renaming PackerTestSuite to PackerPluginTestSuite. Please let me know if I am missing something?

That said, the tests for plugins should be renamed to better indicate what is being tested. For example TestPackerInitForce could be renamed to TestPackerInitWithForceFlag, which read on the screen would be

TestPackerInitWithForceFlag/installs_any_missing_plugins or TestPackerInitWithForceFlag/reinstalls_plugins_matching_version_constraints

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah I agree, naming could definitely be improved here, as we add more tests we'll need to figure out some naming scheme to make things clearer.

Assert(MustFail(),
Grep("Duplicate local definition"),
Grep("Local variable \"test\" is defined twice"))
Assert(lib.MustFail(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first question here is what is lib? Why not just MustFail(). The generic name lib gives no information on the relation of MustFail() to the test suite.

What do you think if we renamed Assert to RunAndAssert to make it clear that Assert runs the test suite and succeeds if the asserts are true?

RunAndAssert(
  MustFail(), 
  Grep("Duplicate local definition"), 
  Grep("Local variable \"test\" is defined twice"))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib is the common parts, so the base TestSuite that you can extend in other packages, and the gadgets for testing, so all the checkers/pipe infrastructure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can name them common too if you prefer? I went with lib because I like the conciseness, but I don't mind renaming this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for renaming Assert to RunAndAssert, I agree it's clearer, but it's also longer, I like terse function names :p
But I'm not fundamentally against the renaming tbh

@nywilken
Copy link
Contributor

Then we have two separate test suites: one for plugins, and one for core itself, the latter of which does not depend on plugins being compiled at all.

With the proper naming conventions I think we could run tests in using the run filter on go test command. Is dynamic plugin generation an issue or are you concerned that over time things will get slower?

Copy link
Contributor Author

@lbajolet-hashicorp lbajolet-hashicorp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I'd say the two main benefits are extensibility/separation by theme and ability to run test suits in parallel. There's also some organisation concern here, as one directory to rule them all is not necessarily ideal. That being said, maybe it's premature and we can revisit this later, if/when the organisation of the package becomes a problem.

As for running tests with -run, yes it is indeed possible; but by default if the test suites are in the same package, they won't run in Parallel I would think. Though maybe it would be feasible with something like t.Parallel? I'd need to explore that, but then if we keep everything in one big package, I'm worried at some point we'll have a ton of files in one giga directory, which is not necessarily ideal imo.

@@ -1,6 +1,8 @@
package packer_test
package plugin_tests
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah I agree, naming could definitely be improved here, as we add more tests we'll need to figure out some naming scheme to make things clearer.

Assert(MustFail(),
Grep("Duplicate local definition"),
Grep("Local variable \"test\" is defined twice"))
Assert(lib.MustFail(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib is the common parts, so the base TestSuite that you can extend in other packages, and the gadgets for testing, so all the checkers/pipe infrastructure.

Assert(MustFail(),
Grep("Duplicate local definition"),
Grep("Local variable \"test\" is defined twice"))
Assert(lib.MustFail(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can name them common too if you prefer? I went with lib because I like the conciseness, but I don't mind renaming this.

Assert(MustFail(),
Grep("Duplicate local definition"),
Grep("Local variable \"test\" is defined twice"))
Assert(lib.MustFail(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for renaming Assert to RunAndAssert, I agree it's clearer, but it's also longer, I like terse function names :p
But I'm not fundamentally against the renaming tbh

Comment on lines +10 to +15
type PackerCoreTestSuite struct {
*lib.PackerTestSuite
}

func Test_PackerPluginSuite(t *testing.T) {
baseSuite, cleanup := lib.PackerCoreSuite(t)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the difference between the two is mostly that the tests run are not the same, being two separate packages/instances of TestSuite means that both can run in parallel. They also may not have the same needs for plugins for example, so one will have to compile a bunch of plugins, and others don't.
As for the names right now, I picked something somewhat randomly, I'm completely open to rename them to something else if you think it's confusing, no problems here!

@lbajolet-hashicorp lbajolet-hashicorp force-pushed the split_packer_test_suites branch from bc8c395 to db95a73 Compare August 6, 2024 15:13
Copy link
Contributor

@nywilken nywilken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that some of the quick name changes I mentioned haven't been applied yet. However, I think those were mostly minor details since this is additive code. If everything is working well, especially with the new gob refactor, let's go ahead and move forward with it, and we can make adjustments as we continue refining it.

While I don't have specific replacement names at the moment, I wanted to mention that the current names aren't immediately clear to me.

Having only one test suite for the whole of Packer makes it harder to
segregate between test types, and makes for a longer runtime as no tests
run in parallel by default.

This commit splits the packer_test suite into several components in
order to make extension easier.

First we have `lib`: this package embeds the core for running Packer
test suites. This ships facilities to build your own test suite for
Packer core, and exposes convenience methods and structures for building
plugins, packer core, and use it to run a test suite in a temporary
directory.

Then we have two separate test suites: one for plugins, and one for core
itself, the latter of which does not depend on plugins being compiled at
all.

This sets the stage for more specialised test suites in the future, each
of which can run in parallel on different parts of the code.
The compiledPlugins map used to be a global variable, which can be
problematic as we move to independent test suites, since those test
suites run in the same process space, the global variable could point to
now deleted plugin versions/paths in separate suites, which would make
tests fail with random errors.

To avoid this, the map is now scoped to the test suite, and a new copy
is created lazily if used by the test suite.
In terms of organisation, we keep functions that interact with plugins
into its own file, therefore the function that build plugin versions
should really be in plugin.go, not in suite.go.
As a small reorganisation attempt, this commit moves some file-system
oriented functions from plugin.go into its own file so they are more
logically grouped.
When testing a packer build or validate, one common use case is to check
which plugins are loaded and used by Packer to run a command.

This is generally done through Grep, but repeating the same pattern can
be redundant, and if the output changes, all those need to be updated.

Therefore, this commit introduces a PluginsUsed gadget, which can be
orchestrated to ensure a plugin is used, or not used, allowing to check
for multiple plugins at once.
@lbajolet-hashicorp lbajolet-hashicorp merged commit ded0500 into main Aug 13, 2024
11 checks passed
@lbajolet-hashicorp lbajolet-hashicorp deleted the split_packer_test_suites branch August 13, 2024 18:54
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement tech-debt Issues and pull requests related to addressing technical debt or improving the codebase
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants